home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / fs / fsSelect.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  25.9 KB  |  876 lines

  1. /* 
  2.  * fsSelect.c --
  3.  *
  4.  *    Routines to implement the Fs_Select system call.
  5.  *
  6.  *    Features:
  7.  *    1) There is a limit on the number of streams that can be selected.
  8.  *       (This routine silently limits it to 1024.)
  9.  *    2) If the 3 bit masks are NULL, and the timeout value is not 0, 
  10.  *       then Sync_WaitTime is called to wait and FS_TIMEOUT is returned
  11.  *       with numReady = 0.
  12.  *    3) The file-type select routine must handle an empty inFlags value
  13.  *       by setting outFlags to 0.
  14.  *    4) If all bits are cleared in the bit masks, SUCCESS is returned
  15.  *       with numReady = 0.
  16.  
  17.  *
  18.  * Copyright 1986 Regents of the University of California
  19.  * All rights reserved.
  20.  */
  21.  
  22. #ifndef lint
  23. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fs/fsSelect.c,v 9.13 91/10/18 12:13:03 shirriff Exp $ SPRITE (Berkeley)";
  24. #endif not lint
  25.  
  26. #define MACH_UNIX_COMPAT
  27.  
  28. #include <sprite.h>
  29. #include <stdio.h>
  30. #include <errno.h>
  31. #include <assert.h>
  32. #include <mach.h>
  33. #include <fs.h>
  34. #include <fsutil.h>
  35. #include <fsNameOps.h>
  36. #include <fsUnixStubs.h>
  37. #include <procUnixStubs.h>
  38. #include <fsio.h>
  39. #include <sync.h>
  40. #include <list.h>
  41. #include <proc.h>
  42. #include <sig.h>
  43. #include <dbg.h>
  44. #include <timer.h>
  45. #include <rpc.h>
  46. #include <vm.h>
  47.  
  48. static char *errs[] = {"ENOERR", "EPERM", "ENOENT", "ESRCH", "EINTR", "EIO",
  49.         "ENXIO", "E2BIG", "ENOEXEC", "EBADF", "ECHILD", "EAGAIN", "ENOMEM",
  50.         "EACCES", "EFAULT", "ENOTBLK", "EBUSY", "EEXIST", "EXDEV", "ENODEV",
  51.         "ENOTDIR", "EISDIR", "EINVAL", "ENFILE", "EMFILE", "ENOTTY",
  52.         "ETXTBSY", "EFBIG", "ENOSPC", "ESPIPE", "EROFS", "EMLINK", "EPIPE",
  53.         "EDOM", "ERANGE", "EWOULDBLOCK", "EINPROGRESS", "EALREADY", "ENOTSOCK",
  54.         "EDESTADDRREQ", "EMSGSIZE", "EPROTOTYPE", "ENOPROTOOPT",
  55.         "EPROTONOSUPPORT", "ESOCKTNOSUPPORT", "EOPNOTSUPP", "EPFNOSUPPORT",
  56.         "EAFNOSUPPORT", "EADDRINUSE", "EADDRNOTAVAIL", "ENETDOWN",
  57.         "ENETUNREACH", "ENETRESET", "ECONNABORTED", "ECONNRESET", "ENOBUFS",
  58.         "EISCONN", "ENOTCONN", "ESHUTDOWN", "ETIMEDOUT", "ECONNREFUSED",
  59.         "ELOOP", "ENAMETOOLONG", "EHOSTDOWN", "EHOSTUNREACH", "ENOTEMPTY",
  60.         "EPROCLIM", "EUSERS", "EDQUOT", "ESTALE", "EREMOTE"};
  61.  
  62. #undef Mach_SetErrno
  63. #define Mach_SetErrno(err) if (debugFsStubs) { \
  64.         printf("Error %d (%s) at %d in %s\n", err,\
  65.         err<sizeof(errs)/sizeof(char *)?errs[err]:"",\
  66.         __LINE__, __FILE__); } Proc_GetActualProc()->unixErrno = (err)
  67.  
  68. /*
  69.  * Internal limit on the number of streams that can be checked.
  70.  * This needs to be moved to an external header file!!
  71.  */
  72. #define MAX_NUM_STREAMS        1024
  73.  
  74. /*
  75.  * Number of bits within a row of the bitmask. Assumes a row
  76.  * is a 32-bit integer.
  77.  */
  78. #define BITS_PER_ROW    32
  79.  
  80. /*
  81.  * Maximum number of rows of bitmasks.
  82.  */
  83. #define MAX_NUM_ROWS    (MAX_NUM_STREAMS / BITS_PER_ROW)
  84.  
  85.  
  86. /*
  87.  * Structure passed to the timeout proc to allow the process to be woken up.
  88.  */
  89. typedef struct {
  90.     Proc_ControlBlock    *procPtr;
  91.     int            timeOut;
  92. } WakeupInfo;
  93.  
  94. /*
  95.  * Routine called in FsSelect if the call timed-out.
  96.  */
  97. static void TimeoutProc _ARGS_((Timer_Ticks ticks, ClientData clientData));
  98.  
  99. static ReturnStatus readInMasks _ARGS_ ((int wordsInMask, int *userReadMaskPtr,
  100.     int *readMaskPtr, int *userWriteMaskPtr, int *writeMaskPtr,
  101.     int *userExceptMaskPtr, int *exceptMaskPtr));
  102.  
  103. static ReturnStatus writeOutMasks _ARGS_ ((int wordsInMask,
  104.     int *userReadMaskPtr, int *readMaskPtr, int *userWriteMaskPtr, 
  105.     int *writeMaskPtr, int *userExceptMaskPtr, int *exceptMaskPtr));
  106.  
  107. /*
  108.  *----------------------------------------------------------------------
  109.  *
  110.  * Fs_SelectStub --
  111.  *
  112.  *      This is the stub for the Fs_Select system call. The bitmasks
  113.  *    are examined to see if the corresponding stream is readble, writable,
  114.  *    and/or has an exception condition pending. The user may give a
  115.  *    timeout period to limit the amount of time to wait.
  116.  *    This stub checks descriptors 0 to numStreams.
  117.  *    There is a bug here, that we check one descriptor too many, compared
  118.  *    to the Unix select.  However, we read in the number of bytes for
  119.  *    0 to numStreams-1.  This can't be fixed without breaking user
  120.  *    programs, so we're leaving it the way it is.
  121.  *
  122.  * Results:
  123.  *    SUCCESS            - the operation was successful.
  124.  *    FS_TIMEOUT        - if a timeout period was specified, and no
  125.  *                    streams were ready within the time-out period.
  126.  *    SYS_ARG_NOACCESS    - an invalid address for an argument was
  127.  *                  given.
  128.  *    SYS_INVALID_ARG        - an invalid stream ID was given in one
  129.  *                  of the bitmaps.
  130.  *    GEN_ABORTED_BY_SIGNAL    - a signal came in.
  131.  *
  132.  * Side effects:
  133.  *    The process may be put to sleep.
  134.  *
  135.  *----------------------------------------------------------------------
  136.  */
  137. /*ARGSUSED*/
  138. ReturnStatus
  139. Fs_SelectStub(numStreams, userTimeoutPtr, userReadMaskPtr, userWriteMaskPtr, 
  140.     userExceptMaskPtr, numReadyPtr)
  141.     int        numStreams;    /* The length in bits of the read and write 
  142.                  * masks. */
  143.     Time    *userTimeoutPtr;/* Timer value indicating timeout period or
  144.                  * USER_NIL if no timeout. (in/out) */
  145.     int        *userReadMaskPtr;
  146.                 /* A bitmask indicating stream ID's to check
  147.                  * for readability. (in/out) */
  148.     int        *userWriteMaskPtr;
  149.                 /* A bitmask indicating stream ID's to check
  150.                  * for writability. (in/out) */
  151.     int        *userExceptMaskPtr;
  152.                 /* A bitmask indicating stream ID's to check
  153.                  * for exception conditions. (in/out) */
  154.     int        *numReadyPtr;    /* On return indicates the number of streams
  155.                  * ready for I/O. (out) */
  156.  
  157. {
  158.     Time        timeout;    /* Copy of *userTimeoutPtr. */
  159.     Time                *timeoutPtr;
  160.     int                 numReady = 0;
  161.     int                 doTimeout;
  162.     ReturnStatus        status, writeStatus;
  163.     int            inReadMasks[MAX_NUM_ROWS];
  164.     int            inWriteMasks[MAX_NUM_ROWS];
  165.     int            inExceptMasks[MAX_NUM_ROWS];
  166.     int            outReadMasks[MAX_NUM_ROWS];
  167.     int            outWriteMasks[MAX_NUM_ROWS];
  168.     int            outExceptMasks[MAX_NUM_ROWS];
  169.     int                 *inReadMaskPtr;
  170.     int                 *outReadMaskPtr;
  171.     int                 *inWriteMaskPtr;
  172.     int                 *outWriteMaskPtr;
  173.     int                 *inExceptMaskPtr;
  174.     int                 *outExceptMaskPtr;
  175.     int            wordsInMask;
  176.  
  177.  
  178.     /*
  179.      * Make sure the number of streams is in the proper range.
  180.      */
  181.     if (numStreams < 0) {
  182.     return(SYS_INVALID_ARG);
  183.     } else if (numStreams > MAX_NUM_STREAMS) {
  184.     numStreams = MAX_NUM_STREAMS;
  185.     }
  186.  
  187.     if ((userReadMaskPtr == (int *) USER_NIL) &&
  188.         (userWriteMaskPtr == (int *) USER_NIL) &&
  189.         (userExceptMaskPtr == (int *) USER_NIL)) {
  190.     numStreams = -1;
  191.     }
  192.  
  193.     if (userTimeoutPtr == (Time *) USER_NIL) {
  194.     timeoutPtr = (Time *) NIL;
  195.     } else {
  196.     if (Vm_CopyIn(sizeof(Time), (Address) userTimeoutPtr, 
  197.                 (Address) &timeout) != SUCCESS) {
  198.         return(SYS_ARG_NOACCESS);
  199.     }
  200.     timeoutPtr = &timeout;
  201.     }
  202.     if (userReadMaskPtr == USER_NIL) {
  203.     inReadMaskPtr = (int *) NIL;
  204.     outReadMaskPtr = (int *) NIL;
  205.     } else {
  206.     inReadMaskPtr = inReadMasks;
  207.     outReadMaskPtr = outReadMasks;
  208.     }
  209.     if (userWriteMaskPtr == USER_NIL) {
  210.     inWriteMaskPtr = (int *) NIL;
  211.     outWriteMaskPtr = (int *) NIL;
  212.     } else {
  213.     inWriteMaskPtr = inWriteMasks;
  214.     outWriteMaskPtr = outWriteMasks;
  215.     }
  216.     if (userExceptMaskPtr == USER_NIL) {
  217.     inExceptMaskPtr = (int *) NIL;
  218.     outExceptMaskPtr = (int *) NIL;
  219.     } else {
  220.     inExceptMaskPtr = inExceptMasks;
  221.     outExceptMaskPtr = outExceptMasks;
  222.     }
  223.     wordsInMask = (numStreams+(BITS_PER_ROW-1))/BITS_PER_ROW;
  224.     status = readInMasks(wordsInMask, userReadMaskPtr, inReadMaskPtr,
  225.     userWriteMaskPtr, inWriteMaskPtr, userExceptMaskPtr, inExceptMaskPtr);
  226.     if (status != SUCCESS) {
  227.     return(SYS_ARG_NOACCESS);
  228.     }
  229.     status = Fs_Select(numStreams, wordsInMask, timeoutPtr, inReadMaskPtr,
  230.     outReadMaskPtr,
  231.     inWriteMaskPtr, outWriteMaskPtr, inExceptMaskPtr, outExceptMaskPtr,
  232.     &numReady, &doTimeout);
  233.     if (status == SUCCESS || status == FS_TIMEOUT) {
  234.     writeStatus = writeOutMasks(wordsInMask, userReadMaskPtr,
  235.         outReadMaskPtr, userWriteMaskPtr, outWriteMaskPtr,
  236.            userExceptMaskPtr, outExceptMaskPtr);
  237.     if (status == SUCCESS && doTimeout && writeStatus==SUCCESS) {
  238.         writeStatus = Vm_CopyOut(sizeof(timeout), (Address) &timeout, 
  239.                             (Address) userTimeoutPtr);
  240.     }
  241.     if (writeStatus != SUCCESS) {
  242.         status = SYS_ARG_NOACCESS;
  243.     }
  244.     }
  245.     if (Vm_CopyOut(sizeof(*numReadyPtr), (Address) &numReady, 
  246.                    (Address) numReadyPtr) != SUCCESS) {
  247.     status = SYS_ARG_NOACCESS;
  248.     }
  249.     return(status);
  250. }
  251.  
  252. /*
  253.  *----------------------------------------------------------------------
  254.  *
  255.  * Fs_NewSelectStub --
  256.  *
  257.  *      The stub for the "select" Unix system call in Unix compatibility.
  258.  *    This stub checks descriptors 0 to numStreams-1.
  259.  *
  260.  * Results:
  261.  *      Returns -1 on failure.
  262.  *
  263.  * Side effects:
  264.  *      Side effects associated with the system call.
  265.  *
  266.  *
  267.  *----------------------------------------------------------------------
  268.  */
  269. int
  270. Fs_NewSelectStub(numStreams, userReadMaskPtr, userWriteMaskPtr,
  271.               userExceptMaskPtr, userTimeoutPtr)
  272.     int        numStreams;    /* The length in bits of the read and write 
  273.                  * masks. */
  274.     int        *userReadMaskPtr;
  275.                 /* A bitmask indicating stream ID's to check
  276.                  * for readability. (in/out) */
  277.     int        *userWriteMaskPtr;
  278.                 /* A bitmask indicating stream ID's to check
  279.                  * for writability. (in/out) */
  280.     int        *userExceptMaskPtr;
  281.                 /* A bitmask indicating stream ID's to check
  282.                  * for exception conditions. (in/out) */
  283.     Time    *userTimeoutPtr;/* Timer value indicating timeout period or
  284.                  * USER_NIL if no timeout. (in/out) */
  285.  
  286. {
  287.     extern int          debugFsStubs;
  288.     int                 doTimeout;
  289.     ReturnStatus        status, writeStatus;
  290.     int            numReady=0;
  291.     Time        timeout;    /* Copy of *userTimeoutPtr. */
  292.     Time                *timeoutPtr;
  293.     int            inReadMasks[MAX_NUM_ROWS];
  294.     int            inWriteMasks[MAX_NUM_ROWS];
  295.     int            inExceptMasks[MAX_NUM_ROWS];
  296.     int            outReadMasks[MAX_NUM_ROWS];
  297.     int            outWriteMasks[MAX_NUM_ROWS];
  298.     int            outExceptMasks[MAX_NUM_ROWS];
  299.     int                 *inReadMaskPtr;
  300.     int                 *outReadMaskPtr;
  301.     int                 *inWriteMaskPtr;
  302.     int                 *outWriteMaskPtr;
  303.     int                 *inExceptMaskPtr;
  304.     int                 *outExceptMaskPtr;
  305.     int            wordsInMask;
  306.  
  307.     if (debugFsStubs) {
  308.     printf("Fs_NewSelectStub(%d, %x, %x, %x, %x)\n", numStreams,
  309.         userReadMaskPtr, userWriteMaskPtr, userExceptMaskPtr,
  310.         userTimeoutPtr);
  311.     }
  312.  
  313.     /*
  314.      * Unfortunately we have to duplicate a whole bunch of code from
  315.      * Fs_SelectStub, since it has a bug we can't change.
  316.      */
  317.  
  318.     /*
  319.      * Make sure the number of streams is in the proper range.
  320.      */
  321.     if (numStreams < 0) {
  322.     Mach_SetErrno(EINVAL);
  323.     return -1;
  324.     } else if (numStreams > MAX_NUM_STREAMS) {
  325.     numStreams = MAX_NUM_STREAMS;
  326.     }
  327.  
  328.     if ((userReadMaskPtr == (int *) USER_NIL) &&
  329.         (userWriteMaskPtr == (int *) USER_NIL) &&
  330.         (userExceptMaskPtr == (int *) USER_NIL)) {
  331.     numStreams = -1;
  332.     }
  333.  
  334.     if (userTimeoutPtr == (Time *) USER_NIL) {
  335.     timeoutPtr = (Time *) NIL;
  336.     } else {
  337.     if (Vm_CopyIn(sizeof(Time), (Address) userTimeoutPtr, 
  338.                 (Address) &timeout) != SUCCESS) {
  339.         Mach_SetErrno(EFAULT);
  340.         return -1;
  341.     }
  342.     timeoutPtr = &timeout;
  343.     }
  344.     if (userReadMaskPtr == USER_NIL) {
  345.     inReadMaskPtr = (int *) NIL;
  346.     outReadMaskPtr = (int *) NIL;
  347.     } else {
  348.     inReadMaskPtr = inReadMasks;
  349.     outReadMaskPtr = outReadMasks;
  350.     }
  351.     if (userWriteMaskPtr == USER_NIL) {
  352.     inWriteMaskPtr = (int *) NIL;
  353.     outWriteMaskPtr = (int *) NIL;
  354.     } else {
  355.     inWriteMaskPtr = inWriteMasks;
  356.     outWriteMaskPtr = outWriteMasks;
  357.     }
  358.     if (userExceptMaskPtr == USER_NIL) {
  359.     inExceptMaskPtr = (int *) NIL;
  360.     outExceptMaskPtr = (int *) NIL;
  361.     } else {
  362.     inExceptMaskPtr = inExceptMasks;
  363.     outExceptMaskPtr = outExceptMasks;
  364.     }
  365.  
  366.     wordsInMask = (numStreams+(BITS_PER_ROW-1))/BITS_PER_ROW;
  367.     status = readInMasks(wordsInMask, userReadMaskPtr, inReadMaskPtr,
  368.     userWriteMaskPtr, inWriteMaskPtr, userExceptMaskPtr, inExceptMaskPtr);
  369.     if (status != SUCCESS) {
  370.     Mach_SetErrno(EFAULT);
  371.     return -1;
  372.     }
  373.     status = Fs_Select(numStreams-1, wordsInMask, timeoutPtr, inReadMaskPtr,
  374.     outReadMaskPtr,
  375.     inWriteMaskPtr, outWriteMaskPtr, inExceptMaskPtr, outExceptMaskPtr,
  376.     &numReady, &doTimeout);
  377.     if (status == SUCCESS || status == FS_TIMEOUT) {
  378.     writeStatus = writeOutMasks(wordsInMask, userReadMaskPtr,
  379.         outReadMaskPtr, userWriteMaskPtr, outWriteMaskPtr,
  380.         userExceptMaskPtr, outExceptMaskPtr);
  381.     if (status == SUCCESS && doTimeout && writeStatus==SUCCESS) {
  382.         writeStatus = Vm_CopyOut(sizeof(timeout), (Address) &timeout, 
  383.                             (Address) userTimeoutPtr);
  384.     }
  385.     if (writeStatus != SUCCESS) {
  386.         status = SYS_ARG_NOACCESS;
  387.     }
  388.     }
  389.     if (status == SUCCESS) {
  390.     return numReady;
  391.     } else if (status == GEN_ABORTED_BY_SIGNAL) {
  392.     Proc_GetCurrentProc()->unixProgress = PROC_PROGRESS_MIG_RESTART;
  393.     Mach_SetErrno(EINTR);
  394.     return -1;
  395.     } else if (status == FS_TIMEOUT) {
  396.     return 0;
  397.     } else {
  398.     Mach_SetErrno(Compat_MapCode(status));
  399.     return -1;
  400.     }
  401. }
  402.  
  403. /*
  404.  *----------------------------------------------------------------------
  405.  *
  406.  * Fs_Select --
  407.  *
  408.  *      The internal select system call.
  409.  *    This stub checks descriptors 0 to numStreams.
  410.  *    If numStreams is -1, it will wait for timeout, but not check anything.
  411.  *
  412.  * Results:
  413.  *      Returns ReturnStatus.
  414.  *
  415.  * Side effects:
  416.  *      Side effects associated with the system call.
  417.  *
  418.  *
  419.  *----------------------------------------------------------------------
  420.  */
  421. /*ARGSUSED*/
  422. ReturnStatus
  423. Fs_Select(numStreams, wordsInMask, timeoutPtr, inReadMaskPtr, outReadMaskPtr,
  424.     inWriteMaskPtr, outWriteMaskPtr, inExceptMaskPtr, outExceptMaskPtr,
  425.     numReadyPtr, doTimeoutPtr)
  426.     int        numStreams;    /* The length in bits of the read and write 
  427.                  * masks. */
  428.     int        wordsInMask;    /* Number of words in the masks. */
  429.     Time    *timeoutPtr;    /* Timer value indicating timeout period or
  430.                  * NIL if no timeout. (in/out) */
  431.     int        *inReadMaskPtr;
  432.     int        *outReadMaskPtr;
  433.                 /* A bitmask indicating stream ID's to check
  434.                  * for readability. (in/out) */
  435.     int        *inWriteMaskPtr;
  436.     int        *outWriteMaskPtr;
  437.                 /* A bitmask indicating stream ID's to check
  438.                  * for writability. (in/out) */
  439.     int        *inExceptMaskPtr;
  440.     int        *outExceptMaskPtr;
  441.                 /* A bitmask indicating stream ID's to check
  442.                  * for exception conditions. (in/out) */
  443.     int        *numReadyPtr;    /* On return indicates the number of streams
  444.                  * ready for I/O. (out) */
  445.     int         *doTimeoutPtr;                 
  446.  
  447. {
  448.     Proc_ControlBlock    *procPtr;    /* This proc's control block */
  449.     Timer_QueueElement    wakeupElement;    /* Element for timeout. */
  450.     WakeupInfo        wakeupInfo;    /* Passed to timeout routine. */
  451.     Sync_RemoteWaiter    waiter;
  452.     int            row;        /* Index of row of inReadMasks,
  453.                      * inWriteMasks, inExceptMasks. */
  454.     register int    mask;        /* Selects bit within a row of
  455.                      * inReadMasks, inWriteMasks,
  456.                      * inExceptMasks. */
  457.     register int    inReadMask = 0;    /* Contents of a row of inReadMasks. */
  458.     register int    inWriteMask = 0;/* Contents of a row of inWriteMasks. */
  459.     int            inExceptMask = 0;/* Content of a row of inExceptMasks.*/
  460.     register int    bit;        /* Loop counter */
  461.     int            bitMax;        /* Loop terminating condition */
  462.     Boolean        poll;        /* If TRUE, don't wait if the first
  463.                      * check of streams finds that none
  464.                      * are ready now. */
  465.     int            s;        /* Temp copy of numStreams */
  466.     ReturnStatus    status = SUCCESS;
  467.  
  468.     /*
  469.      * If all the masks are NIL, then there aren't any streams to select.
  470.      * Set the numStreams to -1 so we can see if we can return once the
  471.      * timeout argument is examined.
  472.      */
  473.     if ((inReadMaskPtr == (int *) NIL) &&
  474.         (inWriteMaskPtr == (int *) NIL) &&
  475.         (inExceptMaskPtr == (int *) NIL)) {
  476.     numStreams = -1;
  477.     }
  478.  
  479.     /*
  480.      * See if a timeout period was given. If so, set up a timer
  481.      * queue element to call TimeoutProc to wakeup the process.
  482.      * If the timeout is 0 or negative, just poll the streams to
  483.      * see if any are ready.
  484.      */
  485.  
  486.     if (timeoutPtr == (Time *) NIL) {
  487.     poll = FALSE;
  488.     *doTimeoutPtr = FALSE;
  489.     } else {
  490.     if ((timeoutPtr->seconds < 0) || 
  491.         ((timeoutPtr->seconds == 0) && (timeoutPtr->microseconds == 0))) {
  492.  
  493.         /*
  494.          * A zero or negative time was given. Assume the user wants to
  495.          * poll the streams.
  496.          */
  497.         *doTimeoutPtr = FALSE;
  498.         poll = TRUE;
  499.  
  500.     } else if (numStreams == -1) {
  501.  
  502.         /*
  503.          * Special case: nothing to select, but a valid timeout period
  504.          * was specified. Just wait for the timeout to expire.
  505.          */
  506.         if (Sync_WaitTime(*timeoutPtr)) {
  507.         return GEN_ABORTED_BY_SIGNAL;
  508.         } else {
  509.         return FS_TIMEOUT;
  510.         }
  511.     } else {
  512.         Timer_Ticks ticks;
  513.         Timer_Ticks currentTicks;
  514.         wakeupElement.routine = TimeoutProc;
  515.  
  516.         /*
  517.          * Convert the user's timeout value from a relative Time to a 
  518.          * an absolute time in the internal Timer_Ticks units.
  519.          *
  520.          * The value wakeupElement.time is used at the end of this
  521.          * routine to return the amount of time remaining in the timeout.
  522.          */
  523.         Timer_TimeToTicks(*timeoutPtr, &ticks);
  524.         Timer_GetCurrentTicks(¤tTicks);
  525.         Timer_AddTicks(currentTicks, ticks, &(wakeupElement.time));
  526.         poll = FALSE;
  527.         *doTimeoutPtr = TRUE;
  528.     }
  529.     }
  530.  
  531.     /*
  532.      * Nothing to select and no timeout specified so just return.
  533.      */
  534.     if (numStreams == -1) {
  535.     return status;
  536.     }
  537.  
  538.     procPtr = Proc_GetCurrentProc();
  539.  
  540.     /*
  541.      * If a timeout period was specified, set up a callback from the Timer 
  542.      * queue.
  543.      */
  544.     wakeupInfo.timeOut = FALSE;
  545.     if (*doTimeoutPtr) {
  546.     wakeupElement.clientData = (ClientData) &wakeupInfo;
  547.     wakeupInfo.procPtr = procPtr;
  548.     Timer_ScheduleRoutine(&wakeupElement, FALSE);
  549.     }
  550.  
  551.     waiter.hostID = rpc_SpriteID;
  552.  
  553.     while (TRUE) {
  554.  
  555.     /*
  556.      * Get the token to use for select waiting.  We must get the token
  557.      * before checking the timeout flag because there is a race 
  558.      * condition between the timeout wakeup and us getting the
  559.      * wait token.  If we checked timeOut before getting the token, it 
  560.      * is possible that a time out could come between checking the 
  561.      * flag and getting the wait token and we could miss the time out.
  562.      */
  563.     Sync_GetWaitToken(&waiter.pid, &waiter.waitToken);
  564.     if (wakeupInfo.timeOut) {
  565.         status = FS_TIMEOUT;
  566.         break;
  567.     }
  568.  
  569.     /*
  570.      * The read, write and except bit masks can be considered as
  571.      * arrays of bits, possibly more than 32 bits long. Each mask is
  572.      * represented as an array of ints such that row 0 corresponds to
  573.      * streams 0 through 31, row 1 corresponds to streams 32 though
  574.      * 63, etc. Within a row, the low-order bit corresponds to the
  575.      * smallest stream number.
  576.      */
  577.     s = numStreams + 1;
  578.     for (row = 0; row < wordsInMask; row++) {
  579.         int    outReadMask = 0;
  580.         int    outWriteMask = 0;
  581.         int    outExceptMask = 0;
  582.  
  583.         if (inReadMaskPtr != (int *) NIL) {
  584.         inReadMask = inReadMaskPtr[row];
  585.         }
  586.         if (inWriteMaskPtr != (int *) NIL) {
  587.         inWriteMask = inWriteMaskPtr[row];
  588.         }
  589.         if (inExceptMaskPtr != (int *) NIL) {
  590.         inExceptMask = inExceptMaskPtr[row];
  591.         }
  592.         if (inReadMask != 0 || inWriteMask != 0 || inExceptMask != 0) {
  593.         /*
  594.          * At least one stream in this row was selected. Go through
  595.          * the masks to find the stream number and see if it's ready.
  596.          */
  597.         bitMax = (s > BITS_PER_ROW) ? BITS_PER_ROW : s;
  598.         for (mask = 1, bit = 0; bit < bitMax; mask <<= 1, bit++) {
  599.             /*
  600.              * Set up single bit masks that will be or'ed into
  601.              * the final result masks.
  602.              */
  603.             int readBit = inReadMask & mask;
  604.             int writeBit = inWriteMask & mask;
  605.             int exceptBit = inExceptMask & mask;
  606.  
  607.             if (readBit | writeBit | exceptBit) {
  608.             Fs_Stream    *streamPtr;
  609.  
  610.             if (Fs_GetStreamPtr(procPtr, row * BITS_PER_ROW + bit, 
  611.                             &streamPtr) != SUCCESS) {
  612.                 /*
  613.                  *  A stream was selected that probably 
  614.                  *  wasn't opened.
  615.                  */
  616.                 status = SYS_INVALID_ARG;
  617.                 goto deschedule;
  618.             } else {
  619.                 if (!(streamPtr->flags & FS_READ)) {
  620.                 readBit = 0;
  621.                 }
  622.                 if (!(streamPtr->flags & FS_WRITE)) {
  623.                 writeBit = 0;
  624.                 }
  625.                 /*
  626.                  * Call the I/O handle's select routine and
  627.                  * combine what's left in the single bit masks
  628.                  * into the final result masks.
  629.                  */
  630.  
  631.                 assert(((int) streamPtr & 3) == 0);
  632.                 assert(((int) streamPtr->ioHandlePtr & 3) == 0);
  633.  
  634.                 status = 
  635.         (*fsio_StreamOpTable[streamPtr->ioHandlePtr->fileID.type].select)
  636.                 (streamPtr->ioHandlePtr, &waiter,
  637.                  &readBit, &writeBit, &exceptBit);
  638.                 if (status != SUCCESS) {
  639.                 goto deschedule;
  640.                 }
  641.                 if (readBit | writeBit | exceptBit) {
  642.                 outReadMask |= readBit & mask;
  643.                 outWriteMask |= writeBit & mask;
  644.                 outExceptMask |= exceptBit & mask;
  645.                 ++*numReadyPtr;
  646.                 }
  647.             }
  648.             }
  649.         }
  650.         s -= BITS_PER_ROW;
  651.         }
  652.         if (outReadMaskPtr != (int *) NIL) {
  653.         outReadMaskPtr[row]   = outReadMask;
  654.         }
  655.         if (outWriteMaskPtr != (int *) NIL) {
  656.         outWriteMaskPtr[row]  = outWriteMask;
  657.         }
  658.         if (outExceptMaskPtr != (int *) NIL) {
  659.         outExceptMaskPtr[row] = outExceptMask;
  660.         }
  661.     }
  662.  
  663.     /*
  664.      * If at least 1 stream is ready or we're just polling, then quit.
  665.      * Otherwise, wait until we're notified that some stream became
  666.      * ready. When we wake up, start the loop again to find out which 
  667.      * stream(s) became ready.
  668.      */
  669.  
  670.     if (*numReadyPtr > 0 || poll) {
  671.         break;
  672.     } else {
  673.         if (Sync_ProcWait((Sync_Lock *) NIL, TRUE)) {
  674.         status = GEN_ABORTED_BY_SIGNAL;
  675.         break;
  676.         }
  677.     }
  678.     }
  679.  
  680.     /*
  681.      * The wakeupInfo.timedOut flag is set by the routine called from 
  682.      * the timer queue. If the flag is not set, then remove the routine 
  683.      * from the queue.
  684.      */
  685. deschedule:
  686.     if (!wakeupInfo.timeOut && *doTimeoutPtr) {
  687.     Timer_DescheduleRoutine(&wakeupElement);
  688.     }
  689.  
  690.     /*
  691.      * Only copy out the masks if something is ready,
  692.      * or upon a timeout.  (Emacs, in particular, stupidly looks
  693.      * at the read masks after a timeout.).
  694.      */
  695.     if (status == SUCCESS || status == FS_TIMEOUT) {
  696.     if (status != SUCCESS) {
  697.         for (row=0 ; row<wordsInMask ; row++) {
  698.         if (outReadMaskPtr != (int *) NIL) {
  699.             outReadMaskPtr[row] = 0;
  700.         }
  701.         if (outWriteMaskPtr != (int *) NIL) {
  702.             outWriteMaskPtr[row] = 0;
  703.         }
  704.         if (outExceptMaskPtr != (int *) NIL) {
  705.             outExceptMaskPtr[row] = 0;
  706.         }
  707.         }
  708.     }
  709.     if (status == SUCCESS && *doTimeoutPtr) {
  710.         /*
  711.          * A timeout period was given but some stream became ready
  712.          * before the period expired.  Return the amount of time that
  713.          * is remaining in the timeout value.
  714.          */
  715.  
  716.         Timer_Ticks temp;
  717.  
  718.         Timer_GetCurrentTicks(&temp);
  719.         Timer_SubtractTicks(wakeupElement.time, temp, &temp);
  720.         Timer_TicksToTime(temp, timeoutPtr);
  721.     }
  722.     }
  723.     return(status);
  724. }
  725.  
  726.  
  727. /*
  728.  *----------------------------------------------------------------------
  729.  *
  730.  * TimeoutProc --
  731.  *
  732.  *    This routine is called from the Timer queue if a select
  733.  *    call does not complete by a certain time.
  734.  *
  735.  * Results:
  736.  *    None.
  737.  *
  738.  * Side effects:
  739.  *    The timeOut field is set to TRUE. Other processes may be woken up.
  740.  *
  741.  *----------------------------------------------------------------------
  742.  */
  743.  
  744. /*ARGSUSED*/
  745. static void
  746. TimeoutProc(ticks, clientData)
  747.     Timer_Ticks    ticks;
  748.     ClientData    clientData;
  749. {
  750.     WakeupInfo    *wakeupInfoPtr = (WakeupInfo *) clientData;
  751.     wakeupInfoPtr->timeOut = TRUE;
  752.     Sync_ProcWakeup(wakeupInfoPtr->procPtr->processID,
  753.                     wakeupInfoPtr->procPtr->waitToken);
  754. }
  755.  
  756. /*
  757.  *----------------------------------------------------------------------
  758.  *
  759.  * readInMasks --
  760.  *
  761.  *    This routine reads in the select masks from user space.
  762.  *    It reads bits 0 to numStreams-1.
  763.  *
  764.  * Results:
  765.  *    Status.
  766.  *
  767.  * Side effects:
  768.  *    Masks are read in.
  769.  *
  770.  *----------------------------------------------------------------------
  771.  */
  772. static ReturnStatus
  773. readInMasks(wordsInMask, userReadMaskPtr, readMaskPtr,
  774.     userWriteMaskPtr, writeMaskPtr, userExceptMaskPtr, exceptMaskPtr)
  775.     int         wordsInMask;
  776.     int        *userReadMaskPtr;
  777.     int        *readMaskPtr;
  778.     int        *userWriteMaskPtr;
  779.     int        *writeMaskPtr;
  780.     int        *userExceptMaskPtr;
  781.     int        *exceptMaskPtr;
  782. {
  783.     int bytesInMask;
  784.     int status;
  785.  
  786.     if (wordsInMask <= 0) {
  787.     return SUCCESS;
  788.     }
  789.     bytesInMask = wordsInMask*sizeof(int);
  790.  
  791.     /*
  792.      * Copy in the masks from user's address space.
  793.      */
  794.     if (userReadMaskPtr != (int *) USER_NIL) {
  795.     status = Vm_CopyIn(bytesInMask, (Address) userReadMaskPtr, 
  796.                (Address) readMaskPtr);
  797.     if (status != SUCCESS) {
  798.         return(status);
  799.     }
  800.     }
  801.     if (userWriteMaskPtr != (int *) USER_NIL) {
  802.     status = Vm_CopyIn(bytesInMask, (Address) userWriteMaskPtr, 
  803.                 (Address) writeMaskPtr);
  804.     if (status != SUCCESS) {
  805.         return(status);
  806.     }
  807.     }
  808.     if (userExceptMaskPtr != (int *) USER_NIL) {
  809.     status = Vm_CopyIn(bytesInMask, (Address) userExceptMaskPtr, 
  810.                 (Address) exceptMaskPtr);
  811.     if (status != SUCCESS) {
  812.         return(status);
  813.     }
  814.     }
  815.     return SUCCESS;
  816. }
  817. /*
  818.  *----------------------------------------------------------------------
  819.  *
  820.  * writeOutMasks --
  821.  *
  822.  *    This routine writes out the select masks to user space.
  823.  *    It writes bits 0 to numStreams-1.
  824.  *
  825.  * Results:
  826.  *    Status.
  827.  *
  828.  * Side effects:
  829.  *    Masks are written out.
  830.  *
  831.  *----------------------------------------------------------------------
  832.  */
  833.  
  834. static ReturnStatus
  835. writeOutMasks(wordsInMask, userReadMaskPtr, readMaskPtr,
  836.     userWriteMaskPtr, writeMaskPtr, userExceptMaskPtr, exceptMaskPtr)
  837.     int         wordsInMask;
  838.     int        *userReadMaskPtr;
  839.     int        *readMaskPtr;
  840.     int        *userWriteMaskPtr;
  841.     int        *writeMaskPtr;
  842.     int        *userExceptMaskPtr;
  843.     int        *exceptMaskPtr;
  844. {
  845.     int bytesInMask;
  846.     int status;
  847.  
  848.     if (wordsInMask <= 0) {
  849.     return SUCCESS;
  850.     }
  851.     bytesInMask = wordsInMask*sizeof(int);
  852.     if (userReadMaskPtr != (int *)USER_NIL) {
  853.     status = Vm_CopyOut(bytesInMask, (Address) readMaskPtr,
  854.                           (Address) userReadMaskPtr);
  855.     if (status != SUCCESS) {
  856.         return(SYS_ARG_NOACCESS);
  857.     }
  858.     }
  859.     if (userWriteMaskPtr != (int *) USER_NIL) {
  860.     status = Vm_CopyOut(bytesInMask, (Address) writeMaskPtr,
  861.                           (Address) userWriteMaskPtr);
  862.     if (status != SUCCESS) {
  863.         return(SYS_ARG_NOACCESS);
  864.     }
  865.     }
  866.     if (userExceptMaskPtr != (int *) USER_NIL) {
  867.     status = Vm_CopyOut(bytesInMask, (Address) exceptMaskPtr,
  868.                           (Address) userExceptMaskPtr);
  869.     if (status != SUCCESS) {
  870.         return(SYS_ARG_NOACCESS);
  871.     }
  872.     }
  873.     return SUCCESS;
  874. }
  875.  
  876.